import traceback
import playwright
import tornado.web
from apscheduler.schedulers.background import BackgroundScheduler
from concurrent.futures import ThreadPoolExecutor
from handler_base import BaseHandler
import json
import os
import inspect

# 异步模式
import asyncio
from playwright.async_api import Playwright,async_playwright
from browser_session import BrowserSession
from http_manager import FailResponse, SuccessResponse
from playwright.async_api._generated import BrowserContext, Page



class OpenPageHandler(BaseHandler):
    """
    新开一个页面
    """
    async def post(self):
        # 打开并操作页面
        try:
            data = json.loads(self.request.body)
            context_name = data.get("context_name", "default")
            url = data["url"]
            context = await self.browser_session.get_context(context_name)
            page, page_index = await self.browser_session.new_page(context)
            await page.goto(url)
            title = await page.title()
            self.write_success(SuccessResponse(200, {
                                                    "title": title,
                                                    "page_index": page_index
                                                    }))
        except Exception as e:
            error_stack_trace = traceback.format_exc() 
            fail_response = FailResponse(type(e).__name__, error_stack_trace)
            self.write_error(fail_response)

class ElActionHandler(BaseHandler):
    """
    执行元素动作
    """
    async def post(self):
        try:
            data = json.loads(self.request.body)
            context_name = data.get("context_name", "default")
            page_index = data.get("page_index")
            action = data.get("action")
            action_loc = data.get("action_loc")
            params = data.get("action_params", {})
            result_loc = data.get("result_loc")
            context = await self.browser_session.get_context(context_name)
            page, page_index = await self.browser_session.get_page(context, page_index)
            
            locator = page.locator(action_loc)
            action_func = getattr(page, action)
            signature = inspect.signature(action_func)
            func_params = signature.parameters.values()
            params_str = ""
            for param in func_params:
                value = params.get(param.name)
                if value is not None:
                    if isinstance(value, str):
                        params_str += f"{param.name}='{value}', "
                    else:
                        params_str += f"{param.name}={value}, "
            locator.fill
            if params_str:
                await eval(f"locator.{action}({params_str})") 
            else:
                await eval(f"locator.{action}()")
            

            locator_result = page.locator(result_loc)
            text = await locator_result.inner_text()
            html = await locator_result.inner_html()
            all_attributes = await locator_result.evaluate("el => [...el.attributes].reduce((acc, attr) => ({ ...acc, [attr.name]: attr.value }), {})")
            tag_name = await locator_result.evaluate("e => e.tagName.toLowerCase()")
            is_checked = ""
            is_editable = ""
            if tag_name == "input":
                value = await locator_result.evaluate("e => e.value")
                attr_type = await locator_result.get_attribute("type")
                if attr_type and attr_type in ["radio", "checkbox"]:
                    is_checked = await locator_result.is_checked()
                    is_editable = await locator_result.is_editable()

            is_disabled = await locator_result.is_disabled()
            is_enabled = await locator_result.is_enabled()
            is_hidden = await locator_result.is_hidden()
            is_visible = await locator_result.is_visible()
            bounding_box = await locator_result.bounding_box()
            result = {
                "tag_name": tag_name,
                "value": value,
                "text": text,
                "is_checked": is_checked,
                "is_disabled": is_disabled,
                "is_editable": is_editable,
                "is_enabled": is_enabled,
                "is_hidden": is_hidden,
                "is_visible": is_visible,
                "bounding_box": bounding_box,
                "html": html,
            }
            all_attributes.update(result)
            self.write_success(SuccessResponse(200, all_attributes))
        
        except Exception as e:
            error_stack_trace = traceback.format_exc() 
            print(error_stack_trace)
            fail_response = FailResponse(type(e).__name__, error_stack_trace)
            self.write_error(fail_response)

class ClosePageHandler(BaseHandler):
    """
    关闭页面
    """
    async def post(self):
        # 关闭页面
        try:
            data = json.loads(self.request.body)
            context_name = data.get("context_name", "default")
            page_index = int(data["page_index"])
            context = await self.browser_session.get_context(context_name)
            await self.browser_session.close_page(context, page_index)
            self.write_success(SuccessResponse(200))
        except Exception as e:

            error_stack_trace = traceback.format_exc() 
            print(error_stack_trace)
            fail_response = FailResponse(type(e).__name__, error_stack_trace)
            self.write_error(fail_response)


def make_app():
    return tornado.web.Application([
        # (r"/member/(\w*)", DpHandler),
        (r"/openPage", OpenPageHandler),
        (r"/elAction", ElActionHandler),
        (r"/closePage", ClosePageHandler),
    ], static_path=os.path.join(os.path.dirname(__file__), 'static')
    )


app = make_app()
app.listen(address="localhost", port=9225)
tornado.ioloop.IOLoop.current().start()

